﻿using Message;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Timers;
using UnityEngine;

/// <summary>
/// 网络管理
/// </summary>
public class NetMgr : MonoBehaviour
{
    public static NetMgr Instance;
    private Socket socket;
    private byte[] buffer;
    private int size = 1024;
    private int protoId;
    private bool isReceiving = false;
    private List<byte> receiveCache = new List<byte>();
    private bool isSending = false;
    private Queue<byte[]> sendCache = new Queue<byte[]>();
      
    private string ip = "211.159.159.200";
    //private string ip = "127.0.0.1";
    private int port = 6650;

    /// <summary>
    /// 心跳频率 6000毫秒1次
    /// </summary>
    private static float hbRate = 6000;

    private long sendTime = 0;
    private long receiveTime = 0;

    /// <summary>
    /// 定时器
    /// </summary>
    Timer timer = new Timer(hbRate);

    public enum Status
    {
        None,
        Connected,
    };
    public Status status = Status.None;

    public NetMgr()
    {
        timer.Elapsed += new ElapsedEventHandler(HandleMainTimer);
        timer.AutoReset = false;
        timer.Enabled = true;

        buffer = new byte[size];
        receiveCache = new List<byte>();
        sendCache = new Queue<byte[]>();
        Instance = this;
        MsgMgr.Instance.AddListener(typeof(SToCHeatBeat).ToString(), OnHeratBeat);
    }

    public void Connect()
    {
        object[] args = new object[1];
        try
        {
            //socket
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

            //Connect
            socket.Connect(IPAddress.Parse(ip), port);
            //BeginReceive
            socket.BeginReceive(buffer, 0, buffer.Length,
                                SocketFlags.None, EndReceive, buffer);
            socket.SendTimeout = 3;
            Debug.Log("连接成功");

            //状态
            status = Status.Connected;

            args[0] = true;
            MsgMgr.Instance.SendMsg("ConnectBack", args); 

        }
        catch (Exception e)
        {
            Debug.Log("连接失败:" + e.Message);
            args[0] = false;
            MsgMgr.Instance.SendMsg("ConnectBack", args);
        }
    } 

    /// <summary>
    /// 接收回调
    /// </summary>
    /// <param name="ar"></param>
    private void EndReceive(IAsyncResult ar)
    {
        try
        {
            if (socket == null)
            {
                return;
            }
            if (!socket.Connected)
            {
                return;
            }
            int count = socket.EndReceive(ar);
            if (count > 0)
            {
                byte[] data = new byte[count];
                Buffer.BlockCopy(buffer, 0, data, 0, count);
                OnReceive(data);

                socket.BeginReceive(buffer, 0,
                         buffer.Length, SocketFlags.None,
                         EndReceive, buffer);
            }
            else
            {
                //包尺寸有问题，断线处理
                Debug.Log("包尺寸有问题，断线处理");
                status = Status.None;

                object[] args = new object[1];
                args[0] = false;
                MsgMgr.Instance.SendMsg("ConnectBack", args);
                Close();
            }

        }
        catch (Exception e)
        {
            Debug.Log("ReceiveCb失败:" + e.Message);
            status = Status.None;
            object[] args = new object[1];
            args[0] = false;
            MsgMgr.Instance.SendMsg("ConnectBack", args);
            Close();
        }
    }

    /// <summary>
    /// 消息处理
    /// </summary>
    /// <param name="data"></param>
    private void OnReceive(byte[] data)
    {
        //将接收到的数据放入数据池中
        receiveCache.AddRange(data);
        //如果没在读数据
        if (!isReceiving)
        {
            isReceiving = true;
            ReadData();
        }
    }

    /// <summary>
    /// 读取数据
    /// </summary>
    private void ReadData()
    {
        byte[] data = NetCode.Decode(ref protoId, ref receiveCache);

        if (data != null)
        {
            Type protoType = ProtoDic.GetProtoTypeByProtoId(protoId);
            object tos = ProtoBuf.Serializer.Deserialize(protoType, new MemoryStream(data));

            object[] args = new object[1];
            args[0] = tos;

            MsgMgr.Instance.SendMsg(protoType.ToString(), args);
            
            //尾递归，继续读取数据
            ReadData();
        }
        else
        {
            isReceiving = false;
        }
    }

    /// <summary>
    /// 发送
    /// </summary>
    /// <param name="obj"></param>
    public void Send(object obj)
    {
        if (status != Status.Connected)
        {
            Debug.LogError("[Connection]还没链接就发送数据是不好的");
            return;
        }

        if (!ProtoDic.ContainProtoType(obj.GetType()))
        {
            Debug.LogError("未知协议号");
            return;
        }

        byte[] data = NetCode.Encode(obj);
        sendCache.Enqueue(data);
        Send();
    }

    byte[] sendData;
    /// <summary>
    /// 发送
    /// </summary>
    private void Send()
    {
        if (socket == null)
        {
            return;
        }

        if (!socket.Connected)
        {
            return;
        }

        try
        {
            if (sendCache.Count == 0)
            {
                isSending = false;
                return;
            }
            isSending = true;
            sendData = sendCache.Dequeue();
            //Debug.Log("data.Length:" + data.Length); 
            socket.BeginSend(sendData, 0, sendData.Length, SocketFlags.None, null, null);
            isSending = false;
            Send();
        }
        catch (Exception e)
        {
            Debug.Log(e.Message);
        }
    }

    private void FixedUpdate()
    {


    }

    private void HandleMainTimer(object sender, ElapsedEventArgs e)
    {
        HeartBeat();
        timer.Start();
    }

    void HeartBeat()
    {
        //心跳
        if (status == Status.Connected)
        {
            CToSHeatBeat hb = new CToSHeatBeat();
            TimeSpan ts = new TimeSpan(DateTime.Now.Ticks);
            hb.time = (long)ts.TotalMilliseconds;
            sendTime = hb.time;
            Send(hb);
        }
        //断线重连
    }

    void OnHeratBeat(object protocol)
    {
        SToCHeatBeat sthb = protocol as SToCHeatBeat;
        TimeSpan ts = new TimeSpan(DateTime.Now.Ticks);
        receiveTime = (long)ts.TotalMilliseconds;
        Debug.LogWarning("正确的延迟：" + (receiveTime - sendTime) / 2);
    }

    /// <summary>
    /// 关闭连接
    /// </summary>
    /// <returns></returns>
    public void Close()
    {
        if (socket != null)
        {
            try
            {
                if (socket.Connected)
                {
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Disconnect(true);
                    socket.Close();
                }

                Debug.Log("关闭socket");
            }
            catch (Exception e)
            {
                Debug.Log("关闭失败:" + e.Message);
            }
            socket = null;

            status = Status.None;
        }
    }

    //描述
    public string GetDesc(byte[] bytes)
    {
        string str = "";
        if (bytes == null) return str;
        for (int i = 0; i < bytes.Length; i++)
        {
            int b = (int)bytes[i];
            str += b.ToString() + " ";
        }
        return str;
    }

    private void OnApplicationPause(bool pause)
    {
        Close();
    }

    private void OnApplicationFocus(bool focus)
    {
        //重新登录
    }

    /// <summary>
    /// 当应用程序退出或编辑器结束运行
    /// </summary>
    private void OnApplicationQuit()
    {
        Debug.Log("Close");
        Close();
        timer.Stop();
    }
}